package com.yixing.tech.datasync.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yixing.tech.common.base.BusinessException;
import com.yixing.tech.common.convert.ConvertUtils;
import com.yixing.tech.common.CommonConstant;
import com.yixing.tech.common.service.AbstractWmsService;
import com.yixing.tech.datasync.constant.MatLevelEnum;
import com.yixing.tech.datasync.constant.StockOutConstant;
import com.yixing.tech.datasync.entity.BillProdPick;
import com.yixing.tech.datasync.entity.BillSalesOutStock;
import com.yixing.tech.datasync.entity.BillSalesPackOutStock;
import com.yixing.tech.datasync.mapper.BillProdPickMapper;
import com.yixing.tech.datasync.mapper.BillSalesOutStockMapper;
import com.yixing.tech.datasync.mapper.BillSalesPackOutStockMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

import static com.yixing.tech.common.CommonConstant.*;

@Service
@Slf4j
public class StockOutSyncService extends AbstractWmsService {

    @Resource
    BillProdPickMapper billProdPickMapper;

    @Resource
    BillSalesOutStockMapper billSalesOutStockMapper;

    @Resource
    BillSalesPackOutStockMapper billSalesPackOutStockMapper;

    @Value("${tenant-id: 6204cb763da841718ddd1cf8}")
    private String tenantId;

    /**
     * 同步领料出库单数据
     * */
    public void syncBillProdPick() throws BusinessException {
        log.info("syncBillProdPick===================");
        // 查询
        List<BillProdPick> prodPickList = billProdPickMapper.selectList(new QueryWrapper<BillProdPick>().eq("status", 0));
        log.info("同步领料出库数量: {}", prodPickList.size());
        if (CollectionUtils.isEmpty(prodPickList)) {
            return;
        }
        // 找到物料编码
        Set<String> materialCodes = prodPickList.stream().map(BillProdPick::getMaterialCode).collect(Collectors.toSet());
        List<Document> materials = findMaterials(materialCodes);
        Map<String, String> materialAbcMap = new HashMap<>();
        Map<String, Document> materialMap = new HashMap<>();
        materials.forEach(m -> {
            String abc = ConvertUtils.convertIfPossible(m.get("abc"), String.class);
            if (abc == null) {
                String levelId = m.getEmbedded(Arrays.asList("level", "id"), String.class);
                if (levelId != null) {
                    if (CommonConstant.MaterialLevel.A.getCode().equals(levelId)) {
                        abc = A;
                    } else if (CommonConstant.MaterialLevel.B.getCode().equals(levelId)) {
                        abc = B;
                    }
                }
            }
            materialAbcMap.put(m.get("code").toString(), abc);
            materialMap.put(m.get("code").toString(), m);
        });
        // 按ABC分类分组
        // 按照 领料出库单号：ABC分类 进行分组
        Map<String, List<BillProdPick>> prodPickListMap = new HashMap<>();
        for (BillProdPick x : prodPickList) {
            String materialCode = x.getMaterialCode();
            String abc = materialAbcMap.get(materialCode);
            if (StringUtils.isBlank(abc)) {
                throw new BusinessException(String.format("领料出库物料[%s]未设置物料ABC分类信息，同步失败", materialCode));
            }
            String key = x.getSourceBillId();
            prodPickListMap.computeIfAbsent(key, l -> new ArrayList<>()).add(x);
        }

        ObjectMapper objectMapper = new ObjectMapper();

        List<Document> billProdPickList = new LinkedList<>();
        List<Document> dtls = new LinkedList<>();

        for (String k : prodPickListMap.keySet()) {
            List<BillProdPick> v = prodPickListMap.get(k);
            String sourceBillId = k;
            String billOutNo = new ObjectId().toString();
            Document billProdPick = new Document();
            billProdPick.put("billOutNo", billOutNo);
            billProdPick.put("billOutSource", sourceBillId);
            billProdPick.put("billOutType", Document.parse(String.format("{id: ObjectId(\"%s\")}", StockOutConstant.BillOutType.PROD_PICK)));
            billProdPick.put("dept", "");
            billProdPick.put("customer", "");
            billProdPick.put("status", Document.parse(String.format("{id: ObjectId(\"%s\")}", "668f3972889b3e051f663429")));
            billProdPick.put("isProcessing", false);
            billProdPick.put("sourceType", newDocument("id", new ObjectId(CommonConstant.SourceType.sync.getCode())));

            BillProdPick first = v.get(0);
            billProdPick.put("erpSourceBillId", sourceBillId);
            billProdPick.put("erpRuleCode", ObjectUtils.isNotEmpty(first.getRuleCode()) ? first.getRuleCode().trim(): "");
            billProdPick.put("erpBizType", ObjectUtils.isNotEmpty(first.getBizType()) ? first.getBizType().trim(): "");
            billProdPick.put("erpTransactionType", ObjectUtils.isNotEmpty(first.getTransactionType())? first.getTransactionType().trim(): "");
            billProdPick.put("erpCostCenterOrgUnit", ObjectUtils.isNotEmpty(first.getCostCenterOrgUnit()) ? first.getCostCenterOrgUnit().trim(): "");
            billProdPick.put("erpStorageOrgUnit", ObjectUtils.isNotEmpty(first.getStorageOrgUnit()) ? first.getStorageOrgUnit().trim(): "");
            billProdPick.put("erpAdminOrgUnit", ObjectUtils.isNotEmpty(first.getAdminOrgUnit()) ? first.getAdminOrgUnit().trim(): "");

            billProdPick.put("createTime", new Date());
            billProdPick.put("tenantId", tenantId);
            billProdPick.put("isDelete", 0);
            billProdPickList.add(billProdPick);

            for (BillProdPick x : v) {
                String materialCode = x.getMaterialCode();
                Document material = materialMap.get(materialCode);
                if (material == null) {
                    throw new BusinessException(String.format("物料[%s]不存在，同步失败", materialCode));
                }
                Document check = simpleFindOne(StockOutConstant.EntityTemplateId.BILL_PROD_PICK_DET_TEMPLATE,
                        "sourceBillId", x.getSourceBillId(),  "sourceBillEntryId", x.getSourceBillEntryId());
                if (check != null) {
                    throw new BusinessException(String.format("领料出库单明细[%s]已存在，同步失败", x.getSourceBillEntryId()));
                }
                Document dtl = new Document();
                dtl.put("mat", ObjectUtils.isNotEmpty(x.getMaterialCode())? x.getMaterialCode().trim(): "");
                dtl.put("matName", material.get("materialName"));
                dtl.put("batchNo", ObjectUtils.isNotEmpty(x.getBatchNo()) ? x.getBatchNo().trim(): "");
                dtl.put("colorName", ObjectUtils.isNotEmpty(x.getColorName()) ? x.getColorName().trim(): "");
                dtl.put("languageName", ObjectUtils.isNotEmpty(x.getLanguageName()) ? x.getLanguageName().trim(): "");
                List<Document> units = material.getList("unit", Document.class);
                if (!CollectionUtils.isEmpty(units)) {
                    dtl.put("unit", units.get(0).getString("name"));
                }

                Double quantity = ConvertUtils.convertIfPossible(x.getQuantity(), Double.class, null);
                if (quantity == null) {
                    throw new BusinessException(String.format("单据[%s]出库数量不合法，同步失败", x.getSourceBillId()));
                }

                dtl.put("plannedQty", quantity);
                dtl.put("actualQty", 0.0);
                dtl.put("sourceBillId", ObjectUtils.isNotEmpty(x.getSourceBillId()) ? x.getSourceBillId().trim(): "");
                dtl.put("sourceBillEntryId", ObjectUtils.isNotEmpty(x.getSourceBillEntryId())? x.getSourceBillEntryId().trim(): "");
                dtl.put("billOutNo", billOutNo);
                dtl.put("orderNo", ObjectUtils.isNotEmpty(x.getOrderCode()) ? x.getOrderCode().trim(): "");
                dtl.put("prodMatCode", ObjectUtils.isNotEmpty(x.getProductCode()) ? x.getProductCode().trim(): "");
                MatLevelEnum matLevelEnum = MatLevelEnum.getByRawValue(materialAbcMap.get(materialCode));
                if(ObjectUtils.isEmpty(matLevelEnum)) {
                    log.error("物料[{}]的ABC[{}]对应的物料等级不存在，同步失败", materialCode, materialAbcMap.get(materialCode));
                    throw new BusinessException(String.format("物料[%s]的ABC[%s]对应的物料等级不存在，同步失败", materialCode, materialAbcMap.get(materialCode)));
                }
                dtl.put("matLevel", Document.parse(String.format("{id: ObjectId(\"%s\")}", matLevelEnum.getDictValue())));

                dtl.put("erpWarehouse", ObjectUtils.isNotEmpty(x.getWarehouse()) ? x.getWarehouse().trim(): "");
                dtl.put("erpSupplyWarehouse", ObjectUtils.isNotEmpty(x.getSupplyWarehouse()) ? x.getSupplyWarehouse().trim(): "");
                dtl.put("erpCostItem", ObjectUtils.isNotEmpty(x.getCostItem())? x.getCostItem().trim(): "");
                dtl.put("erpReport", false);
                dtl.put("erpAudit", false);
                dtl.put("erpMsg", "");
                dtl.put("erpReportTime", null);
                dtl.put("erpBizDate", null);        // 上报给ERP后，ERP回传给WMS的单据日期

//                dtl.put("abc", materialAbcMap.get(materialCode));

                dtl.put("rawUpperDat", objectMapper.convertValue(x, Map.class));

                dtl.put("createTime", new Date());
                dtl.put("tenantId", tenantId);
                dtl.put("isDelete", 0);
                dtls.add(dtl);
            }
        }

        // 保存
        mongoTemplate.insert(billProdPickList, StockOutConstant.EntityTemplateId.BILL_PROD_PICK_TEMPLATE);
        mongoTemplate.insert(dtls, StockOutConstant.EntityTemplateId.BILL_PROD_PICK_DET_TEMPLATE);

        // 更新状态
        prodPickList.forEach(x -> {x.setStatus(1); x.setUpdateTime(new Date());});
        billProdPickMapper.updateById(prodPickList);

    }

    /**
     * 同步销售出库单数据
     * */
    public void syncBillSalesOutStock() throws BusinessException {
        log.info("syncBillSalesOutStock===================");
        // 查询
        List<BillSalesOutStock> salesOutStockList = billSalesOutStockMapper.selectList(new QueryWrapper<BillSalesOutStock>().eq("status", 0));
        log.info("同步销售出库数量: {}", salesOutStockList.size());
        if (CollectionUtils.isEmpty(salesOutStockList)) {
            return;
        }
        // 找到物料编码
        Set<String> materialCodes = salesOutStockList.stream().map(BillSalesOutStock::getMaterialCode).collect(Collectors.toSet());
        List<Document> materials = findMaterials(materialCodes);
//        Map<String, String> materialAbcMap = new HashMap<>();
        Map<String, Document> materialMap = new HashMap<>();
        materials.forEach(m -> {
//            String abc = ConvertUtils.convertIfPossible(m.get("abc"), String.class);
//            if (abc == null) {
//                String levelId = m.getEmbedded(Arrays.asList("level", "id"), String.class);
//                if (levelId != null) {
//                    if (WmsConstant.MaterialLevel.A.getCode().equals(levelId)) {
//                        abc = A;
//                    } else if (WmsConstant.MaterialLevel.B.getCode().equals(levelId)) {
//                        abc = B;
//                    }
//                }
//            }
//            materialAbcMap.put(m.get("code").toString(), abc);
            materialMap.put(m.get("code").toString(), m);
        });

        // 按照 领料出库单号：ABC分类 进行分组
        Map<String, List<BillSalesOutStock>> salesOutStockListMap = new HashMap<>();
        for (BillSalesOutStock x : salesOutStockList) {
            String materialCode = x.getMaterialCode();
//            String abc = materialAbcMap.get(materialCode);
//            if (StringUtils.isBlank(abc)) {
//                throw new BusinessException(String.format("领料出库物料[%s]未设置物料ABC分类信息，同步失败", materialCode));
//            }
            String key = x.getSourceBillId();
            salesOutStockListMap.computeIfAbsent(key, l -> new ArrayList<>()).add(x);
        }

        ObjectMapper objectMapper = new ObjectMapper();

        List<Document> billSalesOutStockList = new LinkedList<>();
        List<Document> dtls = new LinkedList<>();

        for (String k : salesOutStockListMap.keySet()) {
            List<BillSalesOutStock> v = salesOutStockListMap.get(k);
            String sourceBillId = k;
            String billOutNo = new ObjectId().toString();
            Document billSalesOutStock = new Document();
            billSalesOutStock.put("billOutNo", billOutNo);
            billSalesOutStock.put("billOutSource", sourceBillId);
            billSalesOutStock.put("billOutType", Document.parse(String.format("{id: ObjectId(\"%s\")}", StockOutConstant.BillOutType.SALES_OUT_STOCK)));
            billSalesOutStock.put("dept", "");
            billSalesOutStock.put("customer", "");
            billSalesOutStock.put("status", Document.parse(String.format("{id: ObjectId(\"%s\")}", "668f3972889b3e051f663429")));
            billSalesOutStock.put("isProcessing", false);
            billSalesOutStock.put("sourceType", newDocument("id", new ObjectId(CommonConstant.SourceType.sync.getCode())));

            BillSalesOutStock first = v.get(0);
            billSalesOutStock.put("erpSourceBillId", sourceBillId);
            billSalesOutStock.put("erpRuleCode", ObjectUtils.isNotEmpty(first.getRuleCode()) ? first.getRuleCode().trim(): "");
            billSalesOutStock.put("erpBizType", ObjectUtils.isNotEmpty(first.getBizType()) ? first.getBizType().trim(): "");
            billSalesOutStock.put("erpTransactionType", ObjectUtils.isNotEmpty(first.getTransactionType())? first.getTransactionType().trim(): "");
            billSalesOutStock.put("erpCostCenterOrgUnit", ObjectUtils.isNotEmpty(first.getCostCenterOrgUnit()) ? first.getCostCenterOrgUnit().trim(): "");
            billSalesOutStock.put("erpStorageOrgUnit", ObjectUtils.isNotEmpty(first.getStorageOrgUnit()) ? first.getStorageOrgUnit().trim(): "");
            billSalesOutStock.put("erpAdminOrgUnit", ObjectUtils.isNotEmpty(first.getAdminOrgUnit()) ? first.getAdminOrgUnit().trim(): "");

            billSalesOutStock.put("createTime", new Date());
            billSalesOutStock.put("tenantId", tenantId);
            billSalesOutStock.put("isDelete", 0);
            billSalesOutStockList.add(billSalesOutStock);

            for (BillSalesOutStock x : v) {
                String materialCode = x.getMaterialCode();
                Document material = materialMap.get(materialCode);
                if (material == null) {
                    throw new BusinessException(String.format("物料[%s]不存在，同步失败", materialCode));
                }
                Document check = simpleFindOne(StockOutConstant.EntityTemplateId.BILL_SALES_OUT_DET_TEMPLATE,
                        "sourceBillId", x.getSourceBillId(),  "sourceBillEntryId", x.getSourceBillEntryId());
                if (check != null) {
                    throw new BusinessException(String.format("领料出库单明细[%s]已存在，同步失败", x.getSourceBillEntryId()));
                }
                Document dtl = new Document();
                dtl.put("mat", ObjectUtils.isNotEmpty(x.getMaterialCode())? x.getMaterialCode().trim(): "");
                dtl.put("matName", material.get("materialName"));
                dtl.put("colorName", ObjectUtils.isNotEmpty(x.getColorName()) ? x.getColorName().trim(): "");
                dtl.put("languageName", ObjectUtils.isNotEmpty(x.getLanguageName()) ? x.getLanguageName().trim(): "");
                List<Document> units = material.getList("unit", Document.class);
                if (!CollectionUtils.isEmpty(units)) {
                    dtl.put("unit", units.get(0).getString("name"));
                }

                Double quantity = ConvertUtils.convertIfPossible(x.getQuantity(), Double.class, null);
                if (quantity == null) {
                    throw new BusinessException(String.format("单据[%s]出库数量不合法，同步失败", x.getSourceBillId()));
                }

                dtl.put("plannedQty", quantity);
                dtl.put("actualQty", quantity);
                dtl.put("sourceBillId", ObjectUtils.isNotEmpty(x.getSourceBillId()) ? x.getSourceBillId().trim(): "");
                dtl.put("sourceBillEntryId", ObjectUtils.isNotEmpty(x.getSourceBillEntryId())? x.getSourceBillEntryId().trim(): "");
                dtl.put("billOutNo", billOutNo);
                dtl.put("orderNo", ObjectUtils.isNotEmpty(x.getOrderCode()) ? x.getOrderCode().trim(): "");

                dtl.put("erpWarehouse", ObjectUtils.isNotEmpty(x.getWarehouse()) ? x.getWarehouse().trim(): "");
                dtl.put("erpReport", false);
                dtl.put("erpAudit", false);
                dtl.put("erpMsg", "");
                dtl.put("erpReportTime", null);
                dtl.put("erpBizDate", null);        // 上报给ERP后，ERP回传给WMS的单据日期

//                dtl.put("abc", materialAbcMap.get(materialCode));

                dtl.put("rawUpperDat", objectMapper.convertValue(x, Map.class));

                dtl.put("createTime", new Date());
                dtl.put("tenantId", tenantId);
                dtl.put("isDelete", 0);
                dtls.add(dtl);
            }
        }

        // 保存
        mongoTemplate.insert(billSalesOutStockList, StockOutConstant.EntityTemplateId.BILL_SALES_OUT_TEMPLATE);
        mongoTemplate.insert(dtls, StockOutConstant.EntityTemplateId.BILL_SALES_OUT_DET_TEMPLATE);

        // 更新状态
        salesOutStockList.forEach(x -> {x.setStatus(1); x.setUpdateTime(new Date());});
        billSalesOutStockMapper.updateById(salesOutStockList);
    }

    /**
     * 同步销售打包出库单数据
     * */
    public void syncBillSalesPackOutStock() throws BusinessException {
        log.info("syncBillSalesPackOutStock===================");
        // 查询
        List<BillSalesPackOutStock> salesPackOutStockList = billSalesPackOutStockMapper.selectList(new QueryWrapper<BillSalesPackOutStock>().eq("status", 0));
        log.info("同步成品领料出库数量: {}", salesPackOutStockList.size());
        if (CollectionUtils.isEmpty(salesPackOutStockList)) {
            return;
        }
        // 找到物料编码
        Set<String> materialCodes = salesPackOutStockList.stream().map(BillSalesPackOutStock::getMaterialCode).collect(Collectors.toSet());
        List<Document> materials = findMaterials(materialCodes);
//        Map<String, String> materialAbcMap = new HashMap<>();
        Map<String, Document> materialMap = new HashMap<>();
        materials.forEach(m -> {
//            String abc = ConvertUtils.convertIfPossible(m.get("abc"), String.class);
//            if (abc == null) {
//                String levelId = m.getEmbedded(Arrays.asList("level", "id"), String.class);
//                if (levelId != null) {
//                    if (WmsConstant.MaterialLevel.A.getCode().equals(levelId)) {
//                        abc = A;
//                    } else if (WmsConstant.MaterialLevel.B.getCode().equals(levelId)) {
//                        abc = B;
//                    }
//                }
//            }
//            materialAbcMap.put(m.get("code").toString(), abc);
            materialMap.put(m.get("code").toString(), m);
        });
        // 按ABC分类分组
        // 按照 领料出库单号：ABC分类 进行分组
        Map<String, List<BillSalesPackOutStock>> salesPackOutStockListMap = new HashMap<>();
        for (BillSalesPackOutStock x : salesPackOutStockList) {
//            String materialCode = x.getMaterialCode();
//            String abc = materialAbcMap.get(materialCode);
//            if (StringUtils.isBlank(abc)) {
//                throw new BusinessException(String.format("领料出库物料[%s]未设置物料ABC分类信息，同步失败", materialCode));
//            }
            String key = x.getSourceBillId();
            salesPackOutStockListMap.computeIfAbsent(key, l -> new ArrayList<>()).add(x);
        }

        ObjectMapper objectMapper = new ObjectMapper();

        List<Document> billSalesPackOutStockList = new LinkedList<>();
        List<Document> dtls = new LinkedList<>();

        for (String k : salesPackOutStockListMap.keySet()) {
            List<BillSalesPackOutStock> v = salesPackOutStockListMap.get(k);
            String sourceBillId = k;
            String billOutNo = new ObjectId().toString();
            Document salesPackOutStock = new Document();
            salesPackOutStock.put("billOutNo", billOutNo);
            salesPackOutStock.put("billOutSource", sourceBillId);
            salesPackOutStock.put("billOutType", Document.parse(String.format("{id: ObjectId(\"%s\")}", StockOutConstant.BillOutType.SALES_PACK_OUT_STOCK)));
            salesPackOutStock.put("dept", "");
            salesPackOutStock.put("customer", "");
            salesPackOutStock.put("status", Document.parse(String.format("{id: ObjectId(\"%s\")}", "668f3972889b3e051f663429")));
            salesPackOutStock.put("isProcessing", false);
            salesPackOutStock.put("sourceType", newDocument("id", new ObjectId(CommonConstant.SourceType.sync.getCode())));

            BillSalesPackOutStock first = v.get(0);
            salesPackOutStock.put("erpSourceBillId", sourceBillId);

            salesPackOutStock.put("createTime", new Date());
            salesPackOutStock.put("tenantId", tenantId);
            salesPackOutStock.put("isDelete", 0);
            billSalesPackOutStockList.add(salesPackOutStock);

            for (BillSalesPackOutStock x : v) {
                String materialCode = x.getMaterialCode();
                Document material = materialMap.get(materialCode);
                if (material == null) {
                    throw new BusinessException(String.format("物料[%s]不存在，同步失败", materialCode));
                }
                Document check = simpleFindOne(StockOutConstant.EntityTemplateId.BILL_SALES_PACK_OUT_DET_TEMPLATE,
                        "sourceBillId", x.getSourceBillId(),  "sourceBillEntryId", x.getSourceBillEntryId());
                if (check != null) {
                    throw new BusinessException(String.format("领料出库单明细[%s]已存在，同步失败", x.getSourceBillEntryId()));
                }
                Document dtl = new Document();
                dtl.put("mat", ObjectUtils.isNotEmpty(x.getMaterialCode())? x.getMaterialCode().trim(): "");
                dtl.put("matName", material.get("materialName"));
                dtl.put("batchNo", ObjectUtils.isNotEmpty(x.getBatchNo()) ? x.getBatchNo().trim(): "");
                dtl.put("colorName", ObjectUtils.isNotEmpty(x.getColorName()) ? x.getColorName().trim(): "");
                dtl.put("languageName", ObjectUtils.isNotEmpty(x.getLanguageName()) ? x.getLanguageName().trim(): "");
                List<Document> units = material.getList("unit", Document.class);
                if (!CollectionUtils.isEmpty(units)) {
                    dtl.put("unit", units.get(0).getString("name"));
                }

                Double quantity = ConvertUtils.convertIfPossible(x.getQuantity(), Double.class, null);
                if (quantity == null) {
                    throw new BusinessException(String.format("单据[%s]出库数量不合法，同步失败", x.getSourceBillId()));
                }

                dtl.put("plannedQty", quantity);
                dtl.put("actualQty", 0.0);
                dtl.put("sourceBillId", ObjectUtils.isNotEmpty(x.getSourceBillId()) ? x.getSourceBillId().trim(): "");
                dtl.put("sourceBillEntryId", ObjectUtils.isNotEmpty(x.getSourceBillEntryId())? x.getSourceBillEntryId().trim(): "");
                dtl.put("billOutNo", billOutNo);
                dtl.put("orderNo", ObjectUtils.isNotEmpty(x.getOrderCode()) ? x.getOrderCode().trim(): "");

                dtl.put("rawUpperDat", objectMapper.convertValue(x, Map.class));

                dtl.put("createTime", new Date());
                dtl.put("tenantId", tenantId);
                dtl.put("isDelete", 0);
                dtls.add(dtl);
            }
        }

        // 保存
        mongoTemplate.insert(billSalesPackOutStockList, StockOutConstant.EntityTemplateId.BILL_SALES_PACK_OUT_TEMPLATE);
        mongoTemplate.insert(dtls, StockOutConstant.EntityTemplateId.BILL_SALES_PACK_OUT_DET_TEMPLATE);

        // 更新状态
        salesPackOutStockList.forEach(x -> {x.setStatus(1); x.setUpdateTime(new Date());});
        billSalesPackOutStockMapper.updateById(salesPackOutStockList);
    }

    private List<Document> findMaterials(Collection<String> materialCodes) {
        Criteria match = newCriteria().and("code").in(materialCodes);
        List<AggregationOperation> operations = new LinkedList<>();
        operations.add(Aggregation.match(match));
        operations.add(Aggregation.lookup("dict", "$unit.id", "_id", "unit"));
        operations.add(Aggregation.lookup("dict", "$level.id", "_id", "level"));
        return aggregateResult(operations, "entity_" + MATERIAL);

    }
}
